/* Copyright ©, 2022, ECARX (Hubei) Technology Co., Ltd. All rights reserved.
 *
 * NOTICE: This file contains information which is confidential and proprietary to ECARX
 * (Hubei) Technology Co., Ltd. and/or other developers. No license to any intellectual
 * property rights contained within this file is either granted or implied except as may be
 * provided in an agreement with ECARX (Hubei) Technology Co., Ltd.
 *
 * Any unauthorized copying or distribution of content from this file in whole or in part
 * is prohibited.
 */
#ifndef ECARX_VHAL_CORE_READ_WRITE_PROPERTY_BUILD_H
#define ECARX_VHAL_CORE_READ_WRITE_PROPERTY_BUILD_H

#include <algorithm>
#include <functional>
#include <map>
#include <tuple>
#include <type_traits>
#include <vector>

#include "cstdint"
#include "vhal_core/persist/Properties.h"
#include "vhal_core/property/TimerBuilder.h"
#include "vhal_core/utils/convert.h"
#include "VHalLog.h"

namespace ecarx::vhal::core::property {

template <typename _TY>
class SetBuild;
template <typename _TY>
class TimerBuild;

template <typename _TY>
class ValueBuild {
    Area* mArea;

  public:
    ValueBuild(Area* area) : mArea(area) {}

    template <typename PROP, typename AREA>
    ValueBuild<_TY>& addDependentProperty(PROP propertyId, AREA areaId) {
        mArea->addProperties(static_cast<int32_t>(propertyId), static_cast<int32_t>(areaId));
        return *this;
    }

    template <typename... SIGNALS>
    SetBuild<_TY> withValueBySignals(PropValueFn<_TY>&& fn, SIGNALS... signal) {
        if constexpr (std::is_same_v<_TY, bool> || std::is_enum_v<_TY> ||
                      std::is_same_v<_TY, int32_t>) {
            auto signalCallback = [fn](Area* area, int64_t timestamp) {
                // 如果时间比设置的时候时间小则不应该执行
                if (area->runnableBySignal(timestamp)) {
                    auto& current = area->getValue();
                    _TY newValue = fn(_TY(current.value.int32Values[0]));
                    area->setInt32Value(static_cast<int32_t>(newValue), area->isSupportPersist());
                }
            };
            (mArea->registerSignalCallback(toInt(signal), signalCallback), ...);
        } else if constexpr (std::is_same_v<_TY, std::vector<int32_t>>) {
            auto signalCallback = [fn](Area* area, int64_t timestamp) {
                if (area->runnableBySignal(timestamp)) {
                    auto& current = area->getValue();
                    _TY newValue = fn(current.value.int32Values);
                    area->setInt32Values(newValue, area->isSupportPersist());
                }
            };
            (mArea->registerSignalCallback(toInt(signal), signalCallback), ...);
        } else if constexpr (std::is_same_v<_TY, int64_t>) {
            auto signalCallback = [fn](Area* area, int64_t timestamp) {
                if (area->runnableBySignal(timestamp)) {
                    auto& current = area->getValue();
                    _TY newValue = fn(current.value.int64Values[0]);
                    area->setInt64Value(newValue, area->isSupportPersist());
                }
            };
            (mArea->registerSignalCallback(toInt(signal), signalCallback), ...);
        } else if constexpr (std::is_same_v<_TY, std::vector<int64_t>>) {
            auto signalCallback = [fn](Area* area, int64_t timestamp) {
                if (area->runnableBySignal(timestamp)) {
                    auto& current = area->getValue();
                    _TY newValue = fn(current.value.int64Values);
                    area->setInt64Values(newValue, area->isSupportPersist());
                }
            };
            (mArea->registerSignalCallback(toInt(signal), signalCallback), ...);
        } else if constexpr (std::is_same_v<_TY, float>) {
            auto signalCallback = [fn](Area* area, int64_t timestamp) {
                if (area->runnableBySignal(timestamp)) {
                    auto& current = area->getValue();
                    _TY newValue = fn(current.value.floatValues[0]);
                    area->setFloatValue(newValue, area->isSupportPersist());
                }
            };
            (mArea->registerSignalCallback(toInt(signal), signalCallback), ...);
        } else if constexpr (std::is_same_v<_TY, std::vector<float>>) {
            auto signalCallback = [fn](Area* area, int64_t timestamp) {
                if (area->runnableBySignal(timestamp)) {
                    auto& current = area->getValue();
                    _TY newValue = fn(current.value.floatValues);
                    area->setFloatValues(newValue, area->isSupportPersist());
                }
            };
            (mArea->registerSignalCallback(toInt(signal), signalCallback), ...);
        } else if constexpr (std::is_same_v<_TY, std::string>) {
            auto signalCallback = [fn](Area* area, int64_t timestamp) {
                if (area->runnableBySignal(timestamp)) {
                    auto& current = area->getValue();
                    _TY newValue = fn(current.value.stringValue);
                    area->setStringValue(newValue, area->isSupportPersist());
                }
            };
            (mArea->registerSignalCallback(toInt(signal), signalCallback), ...);
        } else if constexpr (std::is_same_v<_TY, std::vector<uint8_t>>) {
            auto signalCallback = [fn](Area* area, int64_t timestamp) {
                if (area->runnableBySignal(timestamp)) {
                    auto& current = area->getValue();
                    _TY newValue = fn(current.value.bytes);
                    area->setBytes(newValue, area->isSupportPersist());
                }
            };
            (mArea->registerSignalCallback(toInt(signal), signalCallback), ...);
        } else if constexpr (std::is_same_v<_TY, MixedValue>) {
            auto signalCallback = [fn](Area* area, int64_t timestamp) {
                if (area->runnableBySignal(timestamp)) {
                    auto& current = area->getValue();
                    _TY newValue = fn(current.value);
                    area->setMixedValue(newValue, area->isSupportPersist());
                }
            };
            (mArea->registerSignalCallback(toInt(signal), signalCallback), ...);
        } else {
            auto signalCallback = [fn](Area* area, int64_t timestamp) {
                if (area->runnableBySignal(timestamp)) {
                    auto& current = area->getValue();
                    _TY value = utils::toValue<_TY>(current.value.bytes);
                    _TY newValue = fn(value);
                    std::vector<uint8_t> bytes = utils::toBytes(newValue);
                    area->setBytes(bytes, area->isSupportPersist());
                }
            };
            (mArea->registerSignalCallback(toInt(signal), signalCallback), ...);
        }

        return SetBuild<_TY>(mArea);
    }
};

template <typename _TY>
class ReadWritePropStatusBuilder {
    Area* mArea;

  public:
    ReadWritePropStatusBuilder(Area* area) : mArea(area) {}
    ValueBuild<_TY> immutableStatus(PropertyStatus status) {
        mArea->updateStatus(status);
        return ValueBuild<_TY>(mArea);
    }

    template <typename... SIGNALS>
    ValueBuild<_TY> withStatusBySignals(PropStatusFn&& statusFn, SIGNALS... signal) {
        auto signalCallback = [statusFn](Area* area, int64_t timestamp) {
            PropertyStatus newStatus = statusFn(area->getStatus());
            area->updateStatus(newStatus);
        };
        mArea->setStatusFn([statusFn](Area* area) { return statusFn(area->getStatus()); });
        (mArea->registerSignalCallback(toInt(signal), signalCallback), ...);
        return ValueBuild<_TY>(mArea);
    }
};

template <typename _TY>
class AreaBuild {
    Area* mArea;

  public:
    AreaBuild(Area* area) : mArea(area) {}

    AreaBuild<_TY>& range(_TY min __attribute__((unused)), _TY max __attribute__((unused))) {
        return *this;
    }

    /**
     * @brief The area VehiclePropValue commit mode
     * 
     * @param min 
     * @param max
     * @return AreaBuild<_TY>& 
     */
    AreaBuild<_TY>& vehiclePropValueCommitMode(CommitMode mode) {
        mArea->setPropValueCommitMode(mode);
        return *this;
    }

    ReadWritePropStatusBuilder<_TY> initValue(
        InitFn<_TY>&& fn, PersistType persist = PersistType::Normal,
        std::function<bool()> conditionFn = []() { return true; }) {
        mArea->setPersistType(persist);
        if constexpr (std::is_enum_v<_TY>) {
            mArea->setInitValueFn([fn](Area* area) {
                int32_t value = static_cast<int32_t>(fn());
                auto persist = area->getPersist();
                if (persist != nullptr) {
                    value = persist->getInt32(area->getKey(), value);
                }
                area->setInt32Value(value);
            });
            if (persist == PersistType::DID || persist == PersistType::Profile || persist == PersistType::Preference) {
                mArea->setRecoveryFn([fn, conditionFn](Area* area) {
                    int32_t value = static_cast<int32_t>(fn());
                    auto persist = area->getPersist();
                    if (persist != nullptr) {
                        value = persist->getInt32(area->getKey(), value);
                    }
                    area->setInt32Value(value);
                    if (conditionFn()) {
                        VehiclePropValue setValue;
                        setValue.prop = area->getIProperty()->getPropertyId();
                        setValue.areaId = area->getAreaId();
                        setValue.status = VehiclePropertyStatus::AVAILABLE;
                        setValue.value.int32Values = {value};
                        // 只要设置成功了就表示已经恢复了
                        area->recoveried(area->exeSetFunction(setValue));
                    } else {
                        area->recoveried(true);
                    }
                });
            }
        } else {
            mArea->setInitValueFn([fn](Area* area) {
                std::vector<uint8_t> value = utils::toBytes(fn());
                auto persist = area->getPersist();
                if (persist != nullptr) {
                    value = persist->getBytes(area->getKey(), value);
                }
                area->setBytes(value);
            });
            if (persist == PersistType::DID || persist == PersistType::Profile || persist == PersistType::Preference) {
                mArea->setRecoveryFn([fn, conditionFn](Area* area) {
                    std::vector<uint8_t> value = utils::toBytes(fn());
                    auto persist = area->getPersist();
                    if (persist != nullptr) {
                        value = persist->getBytes(area->getKey(), value);
                    }
                    area->setBytes(value);
                    if (conditionFn()) {
                        VehiclePropValue setValue;
                        setValue.prop = area->getIProperty()->getPropertyId();
                        setValue.areaId = area->getAreaId();
                        setValue.status = VehiclePropertyStatus::AVAILABLE;
                        setValue.value.bytes = value;
                        // 只要设置成功了就表示已经恢复了
                        area->recoveried(area->exeSetFunction(setValue));
                    } else {
                        area->recoveried(true);
                    }
                });
            }
        }
        return ReadWritePropStatusBuilder<_TY>(mArea);
    }
};

template <typename _TY>
class ReadWritePropertyBuilder {
    IProperty* mProperty;

  public:
    ReadWritePropertyBuilder(IProperty* property) : mProperty(property) {}

    ReadWritePropertyBuilder<_TY>& sampleRate(const float minSampleRate, const float maxSampleRate) {
        mProperty->sampleRate(minSampleRate, maxSampleRate);
        return *this;
    }

    ReadWritePropertyBuilder<_TY>& mixedTypeConfig(bool oneStr, bool oneBool, bool oneInt,
                                                   int32_t sizeInt, bool oneLong, int32_t sizeLong,
                                                   bool oneFloat, int32_t sizeFloat,
                                                   int32_t sizeByte) {
        if (std::is_same_v<_TY, MixedValue>) {
            mProperty->mixedTypeConfig(oneStr, oneBool, oneInt, sizeInt, oneLong, sizeLong,
                                       oneFloat, sizeFloat, sizeByte);
        }
        return *this;
    }

    ReadWritePropertyBuilder<_TY>& configArray(std::vector<int32_t> array) {
        mProperty->configArray(array);
        return *this;
    }

    template <typename AREA>
    AreaBuild<_TY> area(AREA&& area) {
        auto areaId = static_cast<int32_t>(area);
        constexpr const auto globalArea = toInt(VehicleArea::GLOBAL);
        return AreaBuild<_TY>(new Area(mProperty, areaId == globalArea ? 0 : areaId));
    }
};

template <typename _TY>
class SetBuild {
    Area* mArea;

  public:
    SetBuild(Area* area) : mArea(area) {}
    TimerBuilder<_TY, ReadWritePropertyBuilder<_TY>> onSetProperty(SetFn<_TY> fn) {
        if constexpr (std::is_enum_v<_TY>) {
            mArea->setSetTask(
                [fn](const VehiclePropValue& value) {
                    if(value.value.int32Values.size() == 0){
                        VHALOG.e("prop:0x%x areaId:%d, onSetProperty int32Values size is 0, return.",
                            value.prop, value.areaId);
                        return;
                    }
                    fn(_TY(value.value.int32Values[0])); 
                });
        } else {
            mArea->setSetTask([fn](const VehiclePropValue& value) {
                fn(utils::toValue<_TY>(value.value.bytes));
            });
        }
        return TimerBuilder<_TY, ReadWritePropertyBuilder<_TY>>(mArea);
    }
};

template <>
inline TimerBuilder<bool, ReadWritePropertyBuilder<bool>> SetBuild<bool>::onSetProperty(
    SetFn<bool> fn) {
    mArea->setSetTask([fn](const VehiclePropValue& value) {
        if(value.value.int32Values.size() == 0){
            VHALOG.e("prop:0x%x areaId:%d, onSetProperty int32Values size is 0, return.",
                value.prop, value.areaId);
            return;
        }
        fn(value.value.int32Values[0] == 1);
    });
    return TimerBuilder<bool, ReadWritePropertyBuilder<bool>>(mArea);
}

template <>
inline TimerBuilder<int32_t, ReadWritePropertyBuilder<int32_t>> SetBuild<int32_t>::onSetProperty(
    SetFn<int32_t> fn) {
    mArea->setSetTask([fn](const VehiclePropValue& value) {
        if(value.value.int32Values.size() == 0){
            VHALOG.e("prop:0x%x areaId:%d, onSetProperty int32Values size is 0, return.",
                value.prop, value.areaId);
            return;
        }
        fn(value.value.int32Values[0]);
    });
    return TimerBuilder<int32_t, ReadWritePropertyBuilder<int32_t>>(mArea);
}

template <>
inline TimerBuilder<std::vector<int32_t>, ReadWritePropertyBuilder<std::vector<int32_t>>>
SetBuild<std::vector<int32_t>>::onSetProperty(SetFn<std::vector<int32_t>> fn) {
    mArea->setSetTask([fn](const VehiclePropValue& value) { fn(value.value.int32Values); });
    return TimerBuilder<std::vector<int32_t>, ReadWritePropertyBuilder<std::vector<int32_t>>>(mArea);
}

template <>
inline TimerBuilder<int64_t, ReadWritePropertyBuilder<int64_t>> SetBuild<int64_t>::onSetProperty(
    SetFn<int64_t> fn) {
    mArea->setSetTask([fn](const VehiclePropValue& value) {
        if(value.value.int64Values.size() == 0){
            VHALOG.e("prop:0x%x areaId:%d, onSetProperty int64Values size is 0, return.",
                value.prop, value.areaId);
            return;
        } 
        fn(value.value.int64Values[0]); 
    });
    return TimerBuilder<int64_t, ReadWritePropertyBuilder<int64_t>>(mArea);
}

template <>
inline TimerBuilder<std::vector<int64_t>, ReadWritePropertyBuilder<std::vector<int64_t>>>
SetBuild<std::vector<int64_t>>::onSetProperty(SetFn<std::vector<int64_t>> fn) {
    mArea->setSetTask([fn](const VehiclePropValue& value) { fn(value.value.int64Values); });
    return TimerBuilder<std::vector<int64_t>, ReadWritePropertyBuilder<std::vector<int64_t>>>(mArea);
}

template <>
inline TimerBuilder<float, ReadWritePropertyBuilder<float>> SetBuild<float>::onSetProperty(
    SetFn<float> fn) {
    mArea->setSetTask([fn](const VehiclePropValue& value) {
        if(value.value.floatValues.size() == 0){
            VHALOG.e("prop:0x%x areaId:%d, onSetProperty floatValues size is 0, return.",
                value.prop, value.areaId);
            return;
        }
        fn(value.value.floatValues[0]);
    });
    return TimerBuilder<float, ReadWritePropertyBuilder<float>>(mArea);
}

template <>
inline TimerBuilder<std::vector<float>, ReadWritePropertyBuilder<std::vector<float>>>
SetBuild<std::vector<float>>::onSetProperty(SetFn<std::vector<float>> fn) {
    mArea->setSetTask([fn](const VehiclePropValue& value) { fn(value.value.floatValues); });
    return TimerBuilder<std::vector<float>, ReadWritePropertyBuilder<std::vector<float>>>(mArea);
}

template <>
inline TimerBuilder<std::string, ReadWritePropertyBuilder<std::string>>
SetBuild<std::string>::onSetProperty(SetFn<std::string> fn) {
    mArea->setSetTask([fn](const VehiclePropValue& value) {
        std::string setValue = value.value.stringValue;
        fn(setValue);
    });
    return TimerBuilder<std::string, ReadWritePropertyBuilder<std::string>>(mArea);
}

template <>
inline TimerBuilder<std::vector<uint8_t>, ReadWritePropertyBuilder<std::vector<uint8_t>>>
SetBuild<std::vector<uint8_t>>::onSetProperty(SetFn<std::vector<uint8_t>> fn) {
    mArea->setSetTask([fn](const VehiclePropValue& value) { fn(value.value.bytes); });
    return TimerBuilder<std::vector<uint8_t>, ReadWritePropertyBuilder<std::vector<uint8_t>>>(mArea);
}

template <>
inline TimerBuilder<MixedValue, ReadWritePropertyBuilder<MixedValue>>
SetBuild<MixedValue>::onSetProperty(SetFn<MixedValue> fn) {
    mArea->setSetTask([fn](const VehiclePropValue& value) { fn(value.value); });
    return TimerBuilder<MixedValue, ReadWritePropertyBuilder<MixedValue>>(mArea);
}

template <>
inline AreaBuild<int32_t>& AreaBuild<int32_t>::range(int32_t min, int32_t max) {
    mArea->getAreaConfig().minInt32Value = min;
    mArea->getAreaConfig().maxInt32Value = max;
    return *this;
}

template <>
inline AreaBuild<int64_t>& AreaBuild<int64_t>::range(int64_t min, int64_t max) {
    mArea->getAreaConfig().minInt64Value = min;
    mArea->getAreaConfig().maxInt64Value = max;
    return *this;
}

template <>
inline AreaBuild<float>& AreaBuild<float>::range(float min, float max) {
    mArea->getAreaConfig().minFloatValue = min;
    mArea->getAreaConfig().maxFloatValue = max;
    return *this;
}

template <>
inline ReadWritePropStatusBuilder<bool> AreaBuild<bool>::initValue(
    InitFn<bool>&& fn, PersistType persist, std::function<bool()> conditionFn) {
    mArea->setPersistType(persist);
    mArea->setInitValueFn([fn](Area* area) {
        bool value = fn();
        auto persist = area->getPersist();
        if (persist != nullptr) {
            value = persist->getBool(area->getKey(), value);
        }
        area->setBoolValue(value);
    });
    if (persist == PersistType::DID || persist == PersistType::Profile || persist == PersistType::Preference) {
        mArea->setRecoveryFn([fn, conditionFn](Area* area) {
            bool value = fn();
            auto persist = area->getPersist();
            if (persist != nullptr) {
                value = persist->getBool(area->getKey(), value);
            }
            area->setBoolValue(value);
            if (conditionFn()) {
                VehiclePropValue setValue;
                setValue.prop = area->getIProperty()->getPropertyId();
                setValue.areaId = area->getAreaId();
                setValue.status = VehiclePropertyStatus::AVAILABLE;
                setValue.value.int32Values = {value};
                // 只要设置成功了就表示已经恢复了
                area->recoveried(area->exeSetFunction(setValue));
            } else {
                area->recoveried(true);
            }
        });
    }
    return ReadWritePropStatusBuilder<bool>(mArea);
}

template <>
inline ReadWritePropStatusBuilder<int32_t> AreaBuild<int32_t>::initValue(
    InitFn<int32_t>&& fn, PersistType persist, std::function<bool()> conditionFn) {
    mArea->setPersistType(persist);
    mArea->setInitValueFn([fn](Area* area) {
        int32_t value = fn();
        auto persist = area->getPersist();
        if (persist != nullptr) {
            value = persist->getInt32(area->getKey(), value);
        }
        area->setInt32Value(value);
    });
    if (persist == PersistType::DID || persist == PersistType::Profile || persist == PersistType::Preference) {
        mArea->setRecoveryFn([fn, conditionFn](Area* area) {
            int32_t value = fn();
            auto persist = area->getPersist();
            if (persist != nullptr) {
                value = persist->getInt32(area->getKey(), value);
            }
            area->setInt32Value(value);
            if (conditionFn()) {
                VehiclePropValue setValue;
                setValue.prop = area->getIProperty()->getPropertyId();
                setValue.areaId = area->getAreaId();
                setValue.status = VehiclePropertyStatus::AVAILABLE;
                setValue.value.int32Values = {value};
                // 只要设置成功了就表示已经恢复了
                area->recoveried(area->exeSetFunction(setValue));
            } else {
                area->recoveried(true);
            }
        });
    }

    return ReadWritePropStatusBuilder<int32_t>(mArea);
}

template <>
inline ReadWritePropStatusBuilder<std::vector<int32_t>> AreaBuild<std::vector<int32_t>>::initValue(
    InitFn<std::vector<int32_t>>&& fn, PersistType persist, std::function<bool()> conditionFn) {
    mArea->setPersistType(persist);
    mArea->setInitValueFn([fn](Area* area) {
        std::vector<int32_t> value = fn();
        auto persist = area->getPersist();
        if (persist != nullptr) {
            value = persist->getInt32Array(area->getKey(), value);
        }
        area->setInt32Values(value);
    });
    if (persist == PersistType::DID || persist == PersistType::Profile || persist == PersistType::Preference) {
        mArea->setRecoveryFn([fn, conditionFn](Area* area) {
            std::vector<int32_t> value = fn();
            auto persist = area->getPersist();
            if (persist != nullptr) {
                value = persist->getInt32Array(area->getKey(), value);
            }
            area->setInt32Values(value);
            if (conditionFn()) {
                VehiclePropValue setValue;
                setValue.prop = area->getIProperty()->getPropertyId();
                setValue.areaId = area->getAreaId();
                setValue.status = VehiclePropertyStatus::AVAILABLE;
                setValue.value.int32Values = value;
                // 只要设置成功了就表示已经恢复了
                area->recoveried(area->exeSetFunction(setValue));
            } else {
                area->recoveried(true);
            }
        });
    }
    return ReadWritePropStatusBuilder<std::vector<int32_t>>(mArea);
}

template <>
inline ReadWritePropStatusBuilder<int64_t> AreaBuild<int64_t>::initValue(
    InitFn<int64_t>&& fn, PersistType persist, std::function<bool()> conditionFn) {
    mArea->setPersistType(persist);
    mArea->setInitValueFn([fn](Area* area) {
        int64_t value = fn();
        auto persist = area->getPersist();
        if (persist != nullptr) {
            value = persist->getInt64(area->getKey(), value);
        }
        area->setInt64Value(value);
    });
    if (persist == PersistType::DID || persist == PersistType::Profile || persist == PersistType::Preference) {
        mArea->setRecoveryFn([fn, conditionFn](Area* area) {
            int64_t value = fn();
            auto persist = area->getPersist();
            if (persist != nullptr) {
                value = persist->getInt64(area->getKey(), value);
            }
            area->setInt64Value(value);
            if (conditionFn()) {
                VehiclePropValue setValue;
                setValue.prop = area->getIProperty()->getPropertyId();
                setValue.areaId = area->getAreaId();
                setValue.status = VehiclePropertyStatus::AVAILABLE;
                setValue.value.int64Values = {value};
                // 只要设置成功了就表示已经恢复了
                area->recoveried(area->exeSetFunction(setValue));
            } else {
                area->recoveried(true);
            }
        });
    }
    return ReadWritePropStatusBuilder<int64_t>(mArea);
}

template <>
inline ReadWritePropStatusBuilder<std::vector<int64_t>> AreaBuild<std::vector<int64_t>>::initValue(
    InitFn<std::vector<int64_t>>&& fn, PersistType persist, std::function<bool()> conditionFn) {
    mArea->setPersistType(persist);
    mArea->setInitValueFn([fn](Area* area) {
        std::vector<int64_t> value = fn();
        auto persist = area->getPersist();
        if (persist != nullptr) {
            value = persist->getInt64Array(area->getKey(), value);
        }
        area->setInt64Values(value);
    });
    if (persist == PersistType::DID || persist == PersistType::Profile || persist == PersistType::Preference) {
        mArea->setRecoveryFn([fn, conditionFn](Area* area) {
            std::vector<int64_t> value = fn();
            auto persist = area->getPersist();
            if (persist != nullptr) {
                value = persist->getInt64Array(area->getKey(), value);
            }
            area->setInt64Values(value);
            if (conditionFn()) {
                VehiclePropValue setValue;
                setValue.prop = area->getIProperty()->getPropertyId();
                setValue.areaId = area->getAreaId();
                setValue.status = VehiclePropertyStatus::AVAILABLE;
                setValue.value.int64Values = value;
                // 只要设置成功了就表示已经恢复了
                area->recoveried(area->exeSetFunction(setValue));
            } else {
                area->recoveried(true);
            }
        });
    }
    return ReadWritePropStatusBuilder<std::vector<int64_t>>(mArea);
}

template <>
inline ReadWritePropStatusBuilder<float> AreaBuild<float>::initValue(
    InitFn<float>&& fn, PersistType persist, std::function<bool()> conditionFn) {
    mArea->setPersistType(persist);
    mArea->setInitValueFn([fn](Area* area) {
        float value = fn();
        auto persist = area->getPersist();
        if (persist != nullptr) {
            value = persist->getFloat(area->getKey(), value);
        }
        area->setFloatValue(value);
    });
    if (persist == PersistType::DID || persist == PersistType::Profile || persist == PersistType::Preference) {
        mArea->setRecoveryFn([fn, conditionFn](Area* area) {
            float value = fn();
            auto persist = area->getPersist();
            if (persist != nullptr) {
                value = persist->getFloat(area->getKey(), value);
            }
            area->setFloatValue(value);
            if (conditionFn()) {
                VehiclePropValue setValue;
                setValue.prop = area->getIProperty()->getPropertyId();
                setValue.areaId = area->getAreaId();
                setValue.status = VehiclePropertyStatus::AVAILABLE;
                setValue.value.floatValues = {value};
                // 只要设置成功了就表示已经恢复了
                area->recoveried(area->exeSetFunction(setValue));
            } else {
                area->recoveried(true);
            }
        });
    }
    return ReadWritePropStatusBuilder<float>(mArea);
}

template <>
inline ReadWritePropStatusBuilder<std::vector<float>> AreaBuild<std::vector<float>>::initValue(
    InitFn<std::vector<float>>&& fn, PersistType persist, std::function<bool()> conditionFn) {
    mArea->setPersistType(persist);
    mArea->setInitValueFn([fn](Area* area) {
        std::vector<float> value = fn();
        auto persist = area->getPersist();
        if (persist != nullptr) {
            value = persist->getFloatArray(area->getKey(), value);
        }
        area->setFloatValues(value);
    });
    if (persist == PersistType::DID || persist == PersistType::Profile || persist == PersistType::Preference) {
        mArea->setRecoveryFn([fn, conditionFn](Area* area) {
            std::vector<float> value = fn();
            auto persist = area->getPersist();
            if (persist != nullptr) {
                value = persist->getFloatArray(area->getKey(), value);
            }
            area->setFloatValues(value);
            if (conditionFn()) {
                VehiclePropValue setValue;
                setValue.prop = area->getIProperty()->getPropertyId();
                setValue.areaId = area->getAreaId();
                setValue.status = VehiclePropertyStatus::AVAILABLE;
                setValue.value.floatValues = value;
                // 只要设置成功了就表示已经恢复了
                area->recoveried(area->exeSetFunction(setValue));
            } else {
                area->recoveried(true);
            }
        });
    }
    return ReadWritePropStatusBuilder<std::vector<float>>(mArea);
}

template <>
inline ReadWritePropStatusBuilder<std::vector<uint8_t>> AreaBuild<std::vector<uint8_t>>::initValue(
    InitFn<std::vector<uint8_t>>&& fn, PersistType persist, std::function<bool()> conditionFn) {
    mArea->setPersistType(persist);
    mArea->setInitValueFn([fn](Area* area) {
        std::vector<uint8_t> value = fn();
        auto persist = area->getPersist();
        if (persist != nullptr) {
            value = persist->getBytes(area->getKey(), value);
        }
        area->setBytes(value);
    });
    if (persist == PersistType::DID || persist == PersistType::Profile || persist == PersistType::Preference) {
        mArea->setRecoveryFn([fn, conditionFn](Area* area) {
            std::vector<uint8_t> value = fn();
            auto persist = area->getPersist();
            if (persist != nullptr) {
                value = persist->getBytes(area->getKey(), value);
            }
            area->setBytes(value);
            if (conditionFn()) {
                VehiclePropValue setValue;
                setValue.prop = area->getIProperty()->getPropertyId();
                setValue.areaId = area->getAreaId();
                setValue.status = VehiclePropertyStatus::AVAILABLE;
                setValue.value.bytes = value;
                // 只要设置成功了就表示已经恢复了
                area->recoveried(area->exeSetFunction(setValue));
            } else {
                area->recoveried(true);
            }
        });
    }
    return ReadWritePropStatusBuilder<std::vector<uint8_t>>(mArea);
}

template <>
inline ReadWritePropStatusBuilder<std::string> AreaBuild<std::string>::initValue(
    InitFn<std::string>&& fn, PersistType persist, std::function<bool()> conditionFn) {
    mArea->setPersistType(persist);
    mArea->setInitValueFn([fn](Area* area) {
        std::string value = fn();
        auto persist = area->getPersist();
        if (persist != nullptr) {
            value = persist->getString(area->getKey(), value);
        }
        area->setStringValue(value);
    });
    if (persist == PersistType::DID || persist == PersistType::Profile || persist == PersistType::Preference) {
        mArea->setRecoveryFn([fn, conditionFn](Area* area) {
            std::string value = fn();
            auto persist = area->getPersist();
            if (persist != nullptr) {
                value = persist->getString(area->getKey(), value);
            }
            area->setStringValue(value);
            if (conditionFn()) {
                VehiclePropValue setValue;
                setValue.prop = area->getIProperty()->getPropertyId();
                setValue.areaId = area->getAreaId();
                setValue.status = VehiclePropertyStatus::AVAILABLE;
                setValue.value.stringValue = value;
                // 只要设置成功了就表示已经恢复了
                area->recoveried(area->exeSetFunction(setValue));
            } else {
                area->recoveried(true);
            }
        });
    }
    return ReadWritePropStatusBuilder<std::string>(mArea);
}

template <>
inline ReadWritePropStatusBuilder<MixedValue> AreaBuild<MixedValue>::initValue(
    InitFn<MixedValue>&& fn, PersistType persist, std::function<bool()> conditionFn) {
    mArea->setPersistType(persist);
    mArea->setInitValueFn([fn](Area* area) {
        MixedValue value = fn();
        auto persist = area->getPersist();
        if (persist != nullptr) {
            std::string int32key = std::string(area->getKey()).append("::int32s");
            std::string int64key = std::string(area->getKey()).append("::int64s");
            std::string floatkey = std::string(area->getKey()).append("::floats");
            std::string strkey = std::string(area->getKey()).append("::str");
            std::string byteskey = std::string(area->getKey()).append("::bytes");
            value.int32Values = persist->getInt32Array(int32key, value.int32Values);
            value.int64Values = persist->getInt64Array(int64key, value.int64Values);
            value.floatValues = persist->getFloatArray(floatkey, value.floatValues);
            value.stringValue = persist->getString(strkey, value.stringValue);
            value.bytes = persist->getBytes(byteskey, value.bytes);
        }
        area->setMixedValue(value);
    });
    if (persist == PersistType::DID || persist == PersistType::Profile || persist == PersistType::Preference) {
        mArea->setRecoveryFn([fn, conditionFn](Area* area) {
            MixedValue value = fn();
            auto persist = area->getPersist();
            if (persist != nullptr) {
                std::string int32key = std::string(area->getKey()).append("::int32s");
                std::string int64key = std::string(area->getKey()).append("::int64s");
                std::string floatkey = std::string(area->getKey()).append("::floats");
                std::string strkey = std::string(area->getKey()).append("::str");
                std::string byteskey = std::string(area->getKey()).append("::bytes");
                value.int32Values = persist->getInt32Array(int32key, value.int32Values);
                value.int64Values = persist->getInt64Array(int64key, value.int64Values);
                value.floatValues = persist->getFloatArray(floatkey, value.floatValues);
                value.stringValue = persist->getString(strkey, value.stringValue);
                value.bytes = persist->getBytes(byteskey, value.bytes);
            }
            area->setMixedValue(value);
            if (conditionFn()) {
                VehiclePropValue setValue;
                setValue.prop = area->getIProperty()->getPropertyId();
                setValue.areaId = area->getAreaId();
                setValue.status = VehiclePropertyStatus::AVAILABLE;
                setValue.value = value;
                area->recoveried(area->exeSetFunction(setValue));
            } else {
                area->recoveried(true);
                // 只要设置成功了就表示已经恢复了
            }
        });
    }
    return ReadWritePropStatusBuilder<MixedValue>(mArea);
}

}  // namespace ecarx::vhal::core::property

#endif